#include "VxlObject.h"
#include <vector>
#include <exception>
#include "../Utils/Globals.h"

namespace Drawables{
	Utils::CustomEffect *VxlObject::effect = 0;
	bool VxlObject::VxlObjectEffectHasBeenSet = false;
	
	VxlObject::VxlObject(void): isInitialized(false), VxlSize (0.5f)
	{
		Vxls = std::vector<Vxl>();
		VxlCount = 0;
		VxlArraySize = 5;

		world = XMMatrixIdentity();
		SetMaterialInfo(0.600672f, 0.668533f);
	}
	
	VxlObject::~VxlObject(void)
	{
		if( VxlObject::VxlObjectEffectHasBeenSet)
		{
			VxlObject::VxlObjectEffectHasBeenSet = false;
			VxlObject::effect->CleanUp();
			delete VxlObject::effect;
		}

		Vxls.clear();
	}

	void VxlObject::SetVxlSize(float newVxlSize){
		if(!isInitialized && VxlCount == 0)
			VxlSize = newVxlSize;
		else if(isInitialized){
			MessageBox( NULL, "Cannot change the Vxl size after I've initialized the object", "Error", MB_OK );
		}
		else if(VxlCount != 0){
			MessageBox( NULL, "Cannot change the Vxl size after I've started adding Vxls to the object", "Error", MB_OK );
		}
	}

	void VxlObject::CreateFromBlueprint(Blueprints::BaseBlueprint blueprint, XMFLOAT4 &color){
		for(int i = 0; i< blueprint.count; i++){
			AddVxl(blueprint.positions[i], color);
		}
	}

	void VxlObject::AddVxl(XMFLOAT3 &pos, XMFLOAT4 &color){
		
		Vxl v = Vxl();
		v.color = color;
		v.positionInObject = XMFLOAT4(pos.x, pos.y, pos.z, 1.0f);
		v.positionInObject.x *= VxlSize;
		v.positionInObject.y *= VxlSize;
		v.positionInObject.z *= VxlSize;
		VxlCount++;
		Vxls.push_back(v);
	}

	void VxlObject::Initialize(){

		if(VxlObject::VxlObjectEffectHasBeenSet == false){
			// Define the input layout
			D3D11_INPUT_ELEMENT_DESC layout[] =
			{
				{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
				{ "TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, sizeof(XMFLOAT4), D3D11_INPUT_PER_VERTEX_DATA, 0 },
			};			

			VxlObject::effect = new Utils::CustomEffect("Vxl.fxo", "VxlTechnique", CUSTOM_EFFECT_TYPE_PIXEL | CUSTOM_EFFECT_TYPE_GEOMETRY | CUSTOM_EFFECT_TYPE_VERTEX, layout, 2);
				
			VxlObject::VxlObjectEffectHasBeenSet = true;

			VxlObject::effect->AddVariable("Projection");
			VxlObject::effect->AddVariable("View");
			VxlObject::effect->AddVariable("World");
			VxlObject::effect->AddVariable("cubeSize");
			VxlObject::effect->AddVariable("CameraPos");
			VxlObject::effect->AddVariable("LightDirection");
			VxlObject::effect->AddVariable("A");
			VxlObject::effect->AddVariable("B");
			VxlObject::effect->AddVariable("rhoOverPi");
			VxlObject::effect->AddVariable("LightColor");
			VxlObject::effect->AddVariable("AmbientColor");
		}

		Vxl* VxlArray = new Vxl[VxlCount];
		for(int i = 0; i<VxlCount; i++){
			VxlArray[i] = Vxls[i];
		}

		D3D11_BUFFER_DESC bd;
		ZeroMemory( &bd, sizeof(bd) );
		bd.Usage = D3D11_USAGE_DEFAULT;
		bd.ByteWidth = sizeof( Vxl ) * VxlCount;
		bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; 
		bd.CPUAccessFlags = 0;
		D3D11_SUBRESOURCE_DATA InitData;
		ZeroMemory( &InitData, sizeof(InitData) );
		InitData.pSysMem = VxlArray;
		Globals::Device->CreateBuffer( &bd, &InitData, &vertexBuffer);		
	}

	void VxlObject::SetPerFrame()
	{
		VxlObject::effect->SetMatrix("Projection",Globals::ActiveCamera->Projection());
		VxlObject::effect->SetMatrix("View", Globals::ActiveCamera->View());

		VxlObject::effect->SetVector("CameraPos", XMVector3Normalize(Globals::ActiveCamera->Position()));
		VxlObject::effect->SetVector("LightDirection", XMVectorNegate(XMVector3Normalize(XMLoadFloat3(&XMFLOAT3(100, 100, 100)))));
		VxlObject::effect->SetVector("LightColor", XMLoadFloat3(&XMFLOAT3(1, 1, 1)));	
		VxlObject::effect->SetVector("AmbientColor", XMLoadFloat3(&XMFLOAT3(0.3f, 0.3f, 0.3f)));	
		
		Globals::Context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_POINTLIST );
		VxlObject::effect->PreDraw();
	}

	void VxlObject::SetPerObjectShaderParameters(){
		VxlObject::effect->SetFloat("A", A);
		VxlObject::effect->SetFloat("B", B);
		VxlObject::effect->SetFloat("rhoOverPi", rhoOverPi);

		VxlObject::effect->SetMatrix("World", world);
		VxlObject::effect->SetFloat("cubeSize", VxlSize);
	}

	void VxlObject::Draw(){
		SetPerObjectShaderParameters();
		// Set vertex buffer
		UINT stride = sizeof( Vxl );
		UINT offset = 0;
		Globals::Context->IASetVertexBuffers( 0, 1, &vertexBuffer, &stride, &offset );
		
		VxlObject::effect->Draw(VxlCount);
		
	}

	void VxlObject::Update(float dt){

	}

}